package com.kyrie.aop;

import com.alibaba.fastjson.JSON;
import com.kyrie.annotation.TransLog;
import com.kyrie.dto.UserLoginDto;
import com.kyrie.system.mybatis.service.IDefaultService;
import com.kyrie.utils.ConvertUtils;
import com.kyrie.utils.GlobalConstants;
import com.kyrie.utils.IActionContext;
import com.kyrie.vo.TransLogVO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.UUID;

/***
 * 描述: 交易日志切面
 *
 * @author wuxiang
 * @date 2020-04-16 15:15
 */
@Aspect
@Component
public class TransLogAop {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    // 线程对象
    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    @Resource(name = "defaultService")
    private IDefaultService service;

    @Value("${kyrie.loginUrl}")
    private String loginUrl;

    // 设置切点
    @Pointcut("@annotation(com.kyrie.annotation.TransLog)")
    public void transLogCut(){

    }

    @Before("transLogCut()")
    public void before(JoinPoint point) {
        long startTime = System.currentTimeMillis();
        threadLocal.set(startTime);
    }

    @AfterReturning(value = "transLogCut()",returning = "rtv")
    public void after(JoinPoint point,Object rtv) {
        TransLogVO transLog = new TransLogVO();
        // 接口耗时
        long endTime = System.currentTimeMillis();
        String transTime = String.valueOf(endTime - threadLocal.get());
        // 释放线程
        threadLocal.remove();
        transLog.setTransTime(transTime);

        //获取连接点的方法签名对象,在该对象中可以获取到目标方法名,所属类的Class等信息
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取注解所属方法相关信息：接口地址、接口描述
        String transCode = signature.getMethod().getAnnotation(TransLog.class).transCode();
        String transDesc = signature.getMethod().getAnnotation(TransLog.class).description();
        transLog.setTransCode(transCode);
        transLog.setTransLogDesc(transDesc);

        // 获取请求对象
        Object[] objects = point.getArgs();
        String requestBody = JSON.toJSONString(objects[0]);
        transLog.setRequestBody(requestBody);

        // 用户信息,判断当前请求是否为登录请求
        String userNo;
        if (loginUrl.equals(transCode)) {
            UserLoginDto userLogin = ConvertUtils.stringToBean(requestBody,UserLoginDto.class);
            userNo = userLogin.getUserNo();
        } else {
            userNo = IActionContext.getUserNo();
        }
        transLog.setTransOperator(userNo);

        // 获取响应对象
        String responseBody = JSON.toJSONString(rtv);
        transLog.setResponseBody(responseBody);

        // 生成logId
        String logId = UUID.randomUUID().toString() + System.currentTimeMillis();
        transLog.setLogId(logId);
        // 记录切面日志
        service.insert(GlobalConstants.NAME_SPACE + "insertTransLog",transLog);
    }

}
